#pragma once
#include <unordered_map>
#include "Connection.hpp"
#include "Epoller.hpp"

class Reactor
{
    const static int N = 64;

public:
    Reactor()
        : _isrunning(false)
    {
    }
    void AddConnection(int fd, uint32_t events, func_t recver, func_t sender, func_t excepter)
    {
        // 1. 创建connection对象
        Connection *con = new Connection(fd);
        con->SetEvents(events);
        con->_R = this;
        con->_recver = recver;
        con->_sender = sender;
        con->_excepter = excepter;

        // 2. 插入到哈希表中
        _conn[fd] = con;

        // 3.设置epoll对于fd的events事件的关心
        _ep.AddEvents(fd, events);
    }
    void EnableReadWrite(int fd, bool readable, bool writeable)
    {
        uint32_t events = (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET;
        if(ConnectionIsExist(fd))
        {
            // 1.修改对事件的关心
            _conn[fd]->SetEvents(events);

            // 2.写到epoll中
            _ep.ModEvents(fd, events);
        }
    }
    void RemoveConnection(int fd)
    {
        if(!ConnectionIsExist(fd))
            return;
        
        // 1.删除epoll对fd的关心
        _ep.DelEvents(fd);

        // 2. 关闭文件描述符
        _conn[fd]->Close();

        // 3. 删除Connection对象
        delete _conn[fd];
        _conn.erase(fd);

    }
    bool ConnectionIsExist(int fd)
    {
        if (_conn.count(fd))
            return true;
        return false;
    }
    void LoopOnce(int timeout)
    {
        int n = _ep.Wait(_epArr, N, timeout);
        for (int i = 0; i < n; i++)
        {
            int socket = _epArr[i].data.fd;
            uint32_t events = _epArr[i].events;
            if (events & EPOLLHUP)
                events |= EPOLLIN | EPOLLOUT;
            if (events & EPOLLERR)
                events |= EPOLLIN | EPOLLOUT;
            if (events & EPOLLIN)
            {
                if (ConnectionIsExist(socket) && _conn[socket]->_recver != nullptr)
                {
                    _conn[socket]->_recver(_conn[socket]);
                }
            }
            else if (events & EPOLLOUT)
            {
                if (ConnectionIsExist(socket) && _conn[socket]->_sender != nullptr)
                {
                    _conn[socket]->_sender(_conn[socket]);
                }
            }
        }
    }
    void Dispatcher()
    {
        _isrunning = true;
        int timeout = 3000;
        while (_isrunning)
        {
            LoopOnce(timeout);
        }
        _isrunning = false;
    }
    ~Reactor()
    {
    }

private:
    std::unordered_map<int, Connection *> _conn;
    struct epoll_event _epArr[N];
    Epoller _ep;
    bool _isrunning;
};